﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


namespace Particles
{
   public abstract class BaseParticleSystem : DrawableGameComponent
    {
        public const int AlphaBlendDrawOrder = 100;
        public const int AdditiveDrawOrder = 200;

        protected Particle_Editor.Game1 game;


        protected Texture2D ParticleTexture;

        private Vector2 TextureOrigin;

        private int NumberOfEffects;

        Particle[] ParticleSystem;

        Queue<Particle> FreeParticles;
        public int FreeParticleCount
        {
            get { return FreeParticles.Count; }
        }



        protected int MinimumNumberOfParticles;
        protected int MaximumNumberOfParticles;

        protected string ParticleTextureFilename;

        protected float MinimumInitialSpeed;
        protected float MaximumInitialSpeed;

        protected float MinimumAcceleration;
        protected float MaximumAcceleration;

        protected float MinimumRotationSpeed;
        protected float MaximumRotationSpeed;

        protected float MinimumLifetime;
        protected float MaximumLifetime;

        protected float MinimumScale;
        protected float MaximumScale;

        protected SpriteBlendMode spriteBlendMode;

       
         protected BaseParticleSystem(Particle_Editor.Game1 game, int NumberOfEffects)
            : base(game)
        {
            this.game = game;
            this.NumberOfEffects = NumberOfEffects;
        }

        public override void Initialize()
        {
            InitializeConstants();

            ParticleSystem = new Particle[NumberOfEffects * MaximumNumberOfParticles];
            FreeParticles = new Queue<Particle>(NumberOfEffects * MaximumNumberOfParticles);
            for (int i = 0; i < ParticleSystem.Length; i++)
            {
                ParticleSystem[i] = new Particle();
                FreeParticles.Enqueue(ParticleSystem[i]);
            }
            base.Initialize();
        }
        protected abstract void InitializeConstants();

        protected override void LoadContent()
        {
            if (string.IsNullOrEmpty(ParticleTextureFilename))
            {
               
            }
            if(Particle_Editor.Game1.UsingExternalTexture == false)
            {
                ParticleTexture = game.Content.Load<Texture2D>(ParticleTextureFilename);
            }

            TextureOrigin.X = ParticleTexture.Width / 2;
            TextureOrigin.Y = ParticleTexture.Height / 2;
            
            base.LoadContent();
        }

        public void AddParticles(Vector2 theLocation)
        {
            int numParticleSystem = Particle_Editor.Game1.randomizer.Next(MinimumNumberOfParticles, MaximumNumberOfParticles);

            for (int i = 0; i < numParticleSystem && FreeParticles.Count > 0; i++)
            {
                Particle theParticle = FreeParticles.Dequeue();
                InitializeParticle(theParticle, theLocation);
            }
        }

        protected virtual Vector2 PickRandomDirection()
        {
            float angle = Particle_Editor.Game1.GetRandomNumber(0, MathHelper.TwoPi);
            return new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
        }

        protected virtual void InitializeParticle(Particle theParticle, Vector2 theLocation)
        {
            Vector2 direction = PickRandomDirection();

           float velocity =
                Particle_Editor.Game1.GetRandomNumber(MinimumInitialSpeed, MaximumInitialSpeed);
            float acceleration =
                Particle_Editor.Game1.GetRandomNumber(MinimumAcceleration, MaximumAcceleration);
            float lifetime =
                Particle_Editor.Game1.GetRandomNumber(MinimumLifetime, MaximumLifetime);
            float scale =
                Particle_Editor.Game1.GetRandomNumber(MinimumScale, MaximumScale);
            float rotationSpeed =
                Particle_Editor.Game1.GetRandomNumber(MinimumRotationSpeed, MaximumRotationSpeed);

            theParticle.Initialize(
                theLocation, velocity * direction, acceleration * direction,
                lifetime, scale, rotationSpeed);
        }

        public override void Update(GameTime gameTime)
        {
            float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

            foreach (Particle p in ParticleSystem)
            {

                if (p.Active)
                {
                    p.Update(dt);
                    if (!p.Active)
                    {
                        Particle_Editor.Game1.TotalParticlesDestroyed++;
                        FreeParticles.Enqueue(p);
                    }
                }
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            game.spriteBatch.Begin(spriteBlendMode);

            foreach (Particle p in ParticleSystem)
            {

                if (!p.Active)
                    continue;

                float normalizedLifetime = p.TimeSinceStart / p.Lifetime;

                float alpha = 4 * normalizedLifetime * (1 - normalizedLifetime);
                Color color = new Color(new Vector4(Particle_Editor.Game1.ParticleColorR, Particle_Editor.Game1.ParticleColorG, Particle_Editor.Game1.ParticleColorB, alpha));

                float scale = p.Scale * (.75f + .25f * normalizedLifetime);

                game.spriteBatch.Draw(ParticleTexture, p.Position, null, color,
                    p.Rotation, TextureOrigin, scale, SpriteEffects.None, 0.0f);
            }

            game.spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}
